#include "camera_config.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>

namespace CameraConfig {

Config Parser::readConfig(QString filename)
{
	Config config;
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		return config;
	}

	QString jsonData = file.readAll();
	file.close();

	QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData.toUtf8());
	QJsonObject jsonObject = jsonDoc.object();

	QJsonObject rootObject = jsonObject.value(Root).toObject();

	config.resolution = getResolution(rootObject.value(Resolution).toArray());
	config.bitwidth = getBitwidth(rootObject.value(Bitwdith).toArray());
	config.color = getColor(rootObject.value(Color).toArray());
	config.analog = getAnalog(rootObject.value(Analog).toArray());
	config.digital = getDigital(rootObject.value(Digital).toArray());
	config.exposure = getExposure(rootObject.value(Exposure).toArray());

	return config;
}

QVector<QSize> Parser::getResolution(const QJsonArray& array)
{
	QVector<QSize> resolutions;
	for (auto& ele : array) {
		QJsonObject sizeObject = ele.toObject().value(Size).toObject();
		int w = sizeObject.value(Width).toInt();
		int h = sizeObject.value(Height).toInt();
		resolutions.push_back({ w, h });
	}
	return resolutions;
}

QVector<int> Parser::getBitwidth(const QJsonArray& array)
{
	QVector<int> bitwidths;
	for (auto& ele : array) {
		bitwidths.push_back(ele.toInt());
	}
	return bitwidths;
}

QStringList Parser::getColor(const QJsonArray& array)
{
	QStringList colors;
	for (auto& ele : array) {
		colors.push_back(ele.toString());
	}
	return colors;
}

QVector<int> Parser::getAnalog(const QJsonArray& array)
{
	QVector<int> analogs;
	for (auto& ele : array) {
		analogs.push_back(ele.toInt());
	}
	return analogs;
}

QVector<int> Parser::getDigital(const QJsonArray& array)
{
	QVector<int> digitals;
	for (auto& ele : array) {
		digitals.push_back(ele.toInt());
	}
	return digitals;
}

QStringList Parser::getExposure(const QJsonArray& array)
{
	QStringList exposures;
	for (auto& ele : array) {
		exposures.push_back(ele.toString());
	}
	return exposures;
}

Command Parser::readCommand(QString filename)
{
	Command command;
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		return command;
	}

	QString jsonData = file.readAll();
	file.close();

	QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData.toUtf8());
	QJsonObject jsonObject = jsonDoc.object();

	const auto resolutionObject = jsonObject.value(Resolution).toObject();
	for (const auto& res : resolutions) {
		auto obj = resolutionObject.value(res).toObject();
		command.resolution[res]["width"] = obj.value("width").toInt();
		command.resolution[res]["height"] = obj.value("height").toInt();
		command.resolution[res]["req"] = obj.value("req").toString().toInt(nullptr, 16);
		command.resolution[res]["sizePerXfer"] = obj.value("sizePerXfer").toInt();
		command.resolution[res]["queueSize"] = obj.value("queueSize").toInt();
		command.resolution[res]["timeout"] = obj.value("timeout").toInt();
	}

	const auto bitwidthObject = jsonObject.value(Bitwdith).toObject();
	command.bitwidth[8] = bitwidthObject.value("8").toString().toInt(nullptr, 16);
	command.bitwidth[12] = bitwidthObject.value("12").toString().toInt(nullptr, 16);

	const auto analogObject = jsonObject.value(Analog).toObject();
	for (auto& a : {1, 2, 4, 8, 16}) {
		command.analog[a] = analogObject.value(QString::number(a)).toString().toInt(nullptr, 16);
	}
	for (auto& arr : analogObject.value("address").toArray()) {
		command.analogAddress.push_back({ uchar(arr.toArray()[0].toString().toInt(nullptr, 16)),
			uchar(arr.toArray()[1].toString().toInt(nullptr, 16)) });
	}
	for (auto& arr : analogObject.value("extra_code").toArray()) {
		command.analogExtraCode.push_back(arr.toString().toInt(nullptr, 16));
	}
	
	const auto exposureObject = jsonObject.value(Exposure).toObject();
	for (const auto& res : resolutions) {
		auto obj = exposureObject.value(res).toObject();
		command.exposure[res][8] = obj.value("8").toInt();
		command.exposure[res][12] = obj.value("12").toInt();
	}
	auto exposureAddrs = exposureObject.value("address").toArray();
	command.exposureAddress = { uchar(exposureAddrs[0].toString().toInt(nullptr, 16)),
		uchar(exposureAddrs[1].toString().toInt(nullptr, 16)) };

	auto maxSize = jsonObject.value("maxSize").toArray();
	command.maxSize = { maxSize[0].toInt(), maxSize[1].toInt() };

	command.queueSize = jsonObject.value("queueSize").toInt();

	return command;
}



const QString Parser::Root = "camera_config";
const QString Parser::Resolution = "resolution";
const QString Parser::Size = "size";
const QString Parser::Width = "width";
const QString Parser::Height = "height";
const QString Parser::Bitwdith = "bitwidth";
const QString Parser::Color = "color";
const QString Parser::Analog = "analog";
const QString Parser::Digital = "digital";
const QString Parser::Exposure = "exposure";

const QVector<QString> Parser::resolutions = {
	"2592", "2048", "1920", "1280", "640", "320"
};

};